package com.cloudkinto.annotate;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import org.mountcloud.graphql.request.result.ResultAttributtes;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 处理GraphqlResultAttribute注解
 *
 * @author long
 */
@Component
public class GraphqlResultAttributesBuilder {
    public static ResultAttributtes[] build(Class<?> source) {
        boolean classAnnotationExist = source.isAnnotationPresent(GraphqlResultAttribute.class);
        Field[] fields = ReflectUtil.getFields(source);
        if (fields.length == 0) {
            return new ResultAttributtes[0];
        }
        ResultAttributtes[] result = new ResultAttributtes[fields.length];
        AtomicInteger index = new AtomicInteger(0);
        for (Field field : fields) {
            if (classAnnotationExist || field.isAnnotationPresent(GraphqlResultAttribute.class)) {
                field.setAccessible(true);
                String fieldName = field.getName();
                ResultAttributtes resultAttributtes = new ResultAttributtes(fieldName);
                ResultAttributtes[] subitem = processType(field);
                if (subitem != null) {
                    resultAttributtes.addResultAttributes(subitem);
                    result[index.getAndIncrement()] = resultAttributtes;
                }
            }
        }
        return removeNullElements(result);
    }

    /**
     * 移除数组中的null元素
     *
     * @param originalArray 原始数组
     * @return 返回移除null元素后的数组
     */
    public static ResultAttributtes[] removeNullElements(ResultAttributtes[] originalArray) {
        if (originalArray == null) {
            // 返回空数组
            return new ResultAttributtes[0];
        }
        return Arrays.stream(originalArray)
                .filter(Objects::nonNull)
                .toArray(ResultAttributtes[]::new);
    }

    /**
     * 处理属性的类型
     *
     * @param field 当前字段
     * @return 返回null时需排除字段(外层被注解标识 ， 内层没有 ， 需要将外层的属性名从ResultAttributtes中排除)
     * @throws IllegalAccessException 获取字段值时抛出的异常
     */
    private static ResultAttributtes[] processType(Field field) {
        Type genericType = field.getGenericType();
        // 基本类型及包装类和String类型不需要处理
        if (TypeCheckUtils.isBasicOrWrapperOrString(genericType)) {
            return new ResultAttributtes[0];
        }
        if (TypeCheckUtils.isTypeMatch(genericType, Collection.class)
                || TypeCheckUtils.isTypeMatch(genericType, List.class)
                || TypeCheckUtils.isTypeMatch(genericType, Set.class)) {
            // List<T> 获取泛型的类型
            Type typeArgument = TypeUtil.getTypeArgument(genericType);
            if (!TypeCheckUtils.isBasicOrWrapperOrString(typeArgument)) {
                ResultAttributtes[] resultAttributtes = build(((Class<?>) typeArgument));
                if (ArrayUtil.isNotEmpty(resultAttributtes)) {
                    return resultAttributtes;
                } else {
                    return null;
                }
            }
        } else {
            return build((Class<?>) genericType);
        }
        return null;
    }
}